package com.redhipps.hips.client.io;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;

import com.google.gwt.json.client.JSONArray;
import com.google.gwt.json.client.JSONNumber;
import com.google.gwt.json.client.JSONObject;
import com.google.gwt.json.client.JSONString;
import com.google.gwt.json.client.JSONValue;
import com.redhipps.hips.client.model.PythonDatastoreKey;
import com.redhipps.hips.client.model.Model;

@Deprecated
public class SerializedModel<T extends Model> implements Serializable {

  private JSONObject jsonObject;

  protected SerializedModel(JSONObject o) {
    this.jsonObject = o;
  }

  public String stringProperty(String key) {
    return jsonObject.get(key).isString().stringValue();
  }

  public int intProperty(String key) {
    return (int) jsonObject.get(key).isNumber().doubleValue();
  }

  public PythonDatastoreKey referenceProperty(String key) {
    return new PythonDatastoreKey(jsonObject.get(key));
  }

  public List<Integer> intListProperty(String key) {
    return createList(jsonObject.get(key).isArray(), intTransformer);
  }

  public boolean hasProperty(String key) {
    return jsonObject.containsKey(key);
  }

  public Object getProperty(String key) {
    JSONValue value = jsonObject.get(key);
    if (value == null) {
      return null;
    }
    if (value.isNumber() != null) {
      return new Double(value.isNumber().doubleValue());
    } else if (value.isString() != null) {
      JSONString str = value.isString();
      if (str instanceof KeyWrapper) {
        return new PythonDatastoreKey(str);
      } else {
        return str.stringValue();
      }
    } else if (value.isArray() != null) {
      return createList(value.isArray(), intTransformer);
    }
    return null;
  }

  public Set<String> keySet() {
    return jsonObject.keySet();
  }

  public void setProperty(String key, String value) {
    jsonObject.put(key, new JSONString(value));
  }

  public void setProperty(String key, int value) {
    jsonObject.put(key, new JSONNumber(value));
  }

  public void setProperty(String key, PythonDatastoreKey value) {
    jsonObject.put(key, new KeyWrapper(value.toString()));
  }

  public void setProperty(String key, List<Integer> value) {
    JSONArray array = new JSONArray();
    for (int i = 0; i < value.size(); i++) {
      array.set(i, new JSONNumber(value.get(i)));
    }
    jsonObject.put(key, array);
  }

  public PythonDatastoreKey key() {
    return new PythonDatastoreKey(jsonObject.get("key"));
  }

  public JSONObject jsonObject() {
    return jsonObject;
  }

  @Override
  public String toString() {
    return jsonObject.toString();
  }

  @Override
  public int hashCode() {
    return jsonObject.hashCode();
  }

  @Override
  public boolean equals(Object o) {
    return jsonObject.equals(o);
  }

  public T deserialize() {
    return null;
  }

  public static SerializedModel createForSerializedJsonValue(JSONValue o) {
    if (o instanceof JSONObject) {
      return new SerializedModel((JSONObject) o);
    }
    throw new IllegalArgumentException();
  }

  public static SerializedModel createNewModel(String type) {
    JSONObject wrapped = new JSONObject();
    wrapped.put("type", new JSONString(type));
    wrapped.put("key", new JSONString("new"));
    return new SerializedModel(wrapped);
  }

  public static String writeModelList(List<SerializedModel> modelList) {
    JSONArray array = new JSONArray();
    for (int i = 0; i < modelList.size(); i++) {
      SerializedModel m = modelList.get(i);
      array.set(i, m.jsonObject);
    }
    return array.toString();
  }

  /**
   * Marker class for key values.
   */
  private static class KeyWrapper extends JSONString {
    public KeyWrapper(String value) {
      super(value);
    }
  }

  private interface JSONValueTransformer<T> {
    T transform(JSONValue value);
  }

  private static final JSONValueTransformer<Integer> intTransformer =
      new JSONValueTransformer<Integer>() {
        public Integer transform(JSONValue value) {
          return new Integer((int) value.isNumber().doubleValue());
        }
      };

  private static <T> List<T> createList(JSONArray array, JSONValueTransformer<T> tx) {
    List<T> jList = new ArrayList<T>(array.size());
    for (int i = 0; i < array.size(); i++) {
      jList.add(tx.transform(array.get(i)));
    }
    return jList;
  }
}
